<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Introduction to Principal Component Analysis (PCA)</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d9/df8/tutorial_root.html">OpenCV Tutorials</a></li><li class="navelem"><a class="el" href="../../d3/dd5/tutorial_table_of_content_other.html">Other tutorials (ml, objdetect, photo, stitching, video)</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Introduction to Principal Component Analysis (PCA) </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><b>Prev Tutorial:</b> <a class="el" href="../../d0/dcc/tutorial_non_linear_svms.html">Support Vector Machines for Non-Linearly Separable Data</a></p>
<table class="doxtable">
<tr>
<th align="right"></th><th align="left"></th></tr>
<tr>
<td align="right">Original author </td><td align="left">Theodore Tsesmelis </td></tr>
<tr>
<td align="right">Compatibility </td><td align="left">OpenCV &gt;= 3.0 </td></tr>
</table>
<h2>Goal </h2>
<p>In this tutorial you will learn how to:</p>
<ul>
<li>Use the OpenCV class <a class="el" href="../../d3/d8d/classcv_1_1PCA.html">cv::PCA</a> to calculate the orientation of an object.</li>
</ul>
<h2>What is PCA? </h2>
<p>Principal Component Analysis (PCA) is a statistical procedure that extracts the most important features of a dataset.</p>
<div class="image">
<img src="../../pca_line.png" alt="pca_line.png"/>
</div>
<p>Consider that you have a set of 2D points as it is shown in the figure above. Each dimension corresponds to a feature you are interested in. Here some could argue that the points are set in a random order. However, if you have a better look you will see that there is a linear pattern (indicated by the blue line) which is hard to dismiss. A key point of PCA is the Dimensionality Reduction. Dimensionality Reduction is the process of reducing the number of the dimensions of the given dataset. For example, in the above case it is possible to approximate the set of points to a single line and therefore, reduce the dimensionality of the given points from 2D to 1D.</p>
<p>Moreover, you could also see that the points vary the most along the blue line, more than they vary along the Feature 1 or Feature 2 axes. This means that if you know the position of a point along the blue line you have more information about the point than if you only knew where it was on Feature 1 axis or Feature 2 axis.</p>
<p>Hence, PCA allows us to find the direction along which our data varies the most. In fact, the result of running PCA on the set of points in the diagram consist of 2 vectors called <em>eigenvectors</em> which are the <em>principal components</em> of the data set.</p>
<div class="image">
<img src="../../pca_eigen.png" alt="pca_eigen.png"/>
</div>
<p>The size of each eigenvector is encoded in the corresponding eigenvalue and indicates how much the data vary along the principal component. The beginning of the eigenvectors is the center of all points in the data set. Applying PCA to N-dimensional data set yields N N-dimensional eigenvectors, N eigenvalues and 1 N-dimensional center point. Enough theory, let’s see how we can put these ideas into code.</p>
<h2>How are the eigenvectors and eigenvalues computed? </h2>
<p>The goal is to transform a given data set <b>X</b> of dimension <em>p</em> to an alternative data set <b>Y</b> of smaller dimension <em>L</em>. Equivalently, we are seeking to find the matrix <b>Y</b>, where <b>Y</b> is the <em>Karhunen–Loève transform</em> (KLT) of matrix <b>X</b>:</p>
<p class="formulaDsp">
\[ \mathbf{Y} = \mathbb{K} \mathbb{L} \mathbb{T} \{\mathbf{X}\} \]
</p>
<p><b>Organize the data set</b></p>
<p>Suppose you have data comprising a set of observations of <em>p</em> variables, and you want to reduce the data so that each observation can be described with only <em>L</em> variables, <em>L</em> &lt; <em>p</em>. Suppose further, that the data are arranged as a set of <em>n</em> data vectors \( x_1...x_n \) with each \( x_i \) representing a single grouped observation of the <em>p</em> variables.</p>
<ul>
<li>Write \( x_1...x_n \) as row vectors, each of which has <em>p</em> columns.</li>
<li>Place the row vectors into a single matrix <b>X</b> of dimensions \( n\times p \).</li>
</ul>
<p><b>Calculate the empirical mean</b></p>
<ul>
<li>Find the empirical mean along each dimension \( j = 1, ..., p \).</li>
<li><p class="startli">Place the calculated mean values into an empirical mean vector <b>u</b> of dimensions \( p\times 1 \).</p>
<p class="formulaDsp">
\[ \mathbf{u[j]} = \frac{1}{n}\sum_{i=1}^{n}\mathbf{X[i,j]} \]
</p>
</li>
</ul>
<p><b>Calculate the deviations from the mean</b></p>
<p>Mean subtraction is an integral part of the solution towards finding a principal component basis that minimizes the mean square error of approximating the data. Hence, we proceed by centering the data as follows:</p>
<ul>
<li>Subtract the empirical mean vector <b>u</b> from each row of the data matrix <b>X</b>.</li>
<li><p class="startli">Store mean-subtracted data in the \( n\times p \) matrix <b>B</b>.</p>
<p class="formulaDsp">
\[ \mathbf{B} = \mathbf{X} - \mathbf{h}\mathbf{u^{T}} \]
</p>
<p class="startli">where <b>h</b> is an \( n\times 1 \) column vector of all 1s:</p>
<p class="formulaDsp">
\[ h[i] = 1, i = 1, ..., n \]
</p>
</li>
</ul>
<p><b>Find the covariance matrix</b></p>
<ul>
<li><p class="startli">Find the \( p\times p \) empirical covariance matrix <b>C</b> from the outer product of matrix <b>B</b> with itself:</p>
<p class="formulaDsp">
\[ \mathbf{C} = \frac{1}{n-1} \mathbf{B^{*}} \cdot \mathbf{B} \]
</p>
<p class="startli">where * is the conjugate transpose operator. Note that if B consists entirely of real numbers, which is the case in many applications, the "conjugate transpose" is the same as the regular transpose.</p>
</li>
</ul>
<p><b>Find the eigenvectors and eigenvalues of the covariance matrix</b></p>
<ul>
<li><p class="startli">Compute the matrix <b>V</b> of eigenvectors which diagonalizes the covariance matrix <b>C</b>:</p>
<p class="formulaDsp">
\[ \mathbf{V^{-1}} \mathbf{C} \mathbf{V} = \mathbf{D} \]
</p>
<p class="startli">where <b>D</b> is the diagonal matrix of eigenvalues of <b>C</b>.</p>
</li>
<li><p class="startli">Matrix <b>D</b> will take the form of an \( p \times p \) diagonal matrix:</p>
<p class="formulaDsp">
\[ D[k,l] = \left\{\begin{matrix} \lambda_k, k = l \\ 0, k \neq l \end{matrix}\right. \]
</p>
<p class="startli">here, \( \lambda_j \) is the <em>j</em>-th eigenvalue of the covariance matrix <b>C</b></p>
</li>
<li>Matrix <b>V</b>, also of dimension <em>p</em> x <em>p</em>, contains <em>p</em> column vectors, each of length <em>p</em>, which represent the <em>p</em> eigenvectors of the covariance matrix <b>C</b>.</li>
<li>The eigenvalues and eigenvectors are ordered and paired. The <em>j</em> th eigenvalue corresponds to the <em>j</em> th eigenvector.</li>
</ul>
<dl class="section note"><dt>Note</dt><dd>sources <a href="https://robospace.wordpress.com/2013/10/09/object-orientation-principal-component-analysis-opencv/">[1]</a>, <a href="http://en.wikipedia.org/wiki/Principal_component_analysis">[2]</a> and special thanks to Svetlin Penkov for the original tutorial.</dd></dl>
<h2>Source Code </h2>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'><ul>
<li><b>Downloadable code</b>: Click <a href="https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ml/introduction_to_pca/introduction_to_pca.cpp">here</a></li>
<li><b>Code at glance:</b> <div class="fragment"><div class="line"></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d0/d9c/core_2include_2opencv2_2core_8hpp.html">opencv2/core.hpp</a>&quot;</span></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d1/d4f/imgproc_2include_2opencv2_2imgproc_8hpp.html">opencv2/imgproc.hpp</a>&quot;</span></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d4/dd5/highgui_8hpp.html">opencv2/highgui.hpp</a>&quot;</span></div><div class="line"><span class="preprocessor">#include &lt;iostream&gt;</span></div><div class="line"></div><div class="line"><span class="keyword">using namespace </span>std;</div><div class="line"><span class="keyword">using namespace </span><a class="code" href="../../d2/d75/namespacecv.html">cv</a>;</div><div class="line"></div><div class="line"><span class="comment">// Function declarations</span></div><div class="line"><span class="keywordtype">void</span> <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(<a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp;, <a class="code" href="../../db/d4e/classcv_1_1Point__.html">Point</a>, <a class="code" href="../../db/d4e/classcv_1_1Point__.html">Point</a>, <a class="code" href="../../d1/da0/classcv_1_1Scalar__.html">Scalar</a>, <span class="keyword">const</span> <span class="keywordtype">float</span>);</div><div class="line"><span class="keywordtype">double</span> getOrientation(<span class="keyword">const</span> vector&lt;Point&gt; &amp;, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp;);</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(<a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; img, <a class="code" href="../../db/d4e/classcv_1_1Point__.html">Point</a> p, <a class="code" href="../../db/d4e/classcv_1_1Point__.html">Point</a> q, <a class="code" href="../../d1/da0/classcv_1_1Scalar__.html">Scalar</a> colour, <span class="keyword">const</span> <span class="keywordtype">float</span> scale = 0.2)</div><div class="line">{</div><div class="line">    <span class="keywordtype">double</span> angle = <a class="code" href="../../df/dfc/group__cudev.html#ga1096ba687de70142e095cc791a8bcd65">atan2</a>( (<span class="keywordtype">double</span>) p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a> - q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a>, (<span class="keywordtype">double</span>) p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a> - q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a> ); <span class="comment">// angle in radians</span></div><div class="line">    <span class="keywordtype">double</span> hypotenuse = <a class="code" href="../../d0/de1/group__core.html#ga9070b6a3f093dd952d973819b06f4906">sqrt</a>( (<span class="keywordtype">double</span>) (p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a> - q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a>) * (p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a> - q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a>) + (p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a> - q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a>) * (p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a> - q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a>));</div><div class="line"></div><div class="line">    <span class="comment">// Here we lengthen the arrow by a factor of scale</span></div><div class="line">    q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a> = (int) (p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a> - scale * hypotenuse * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle));</div><div class="line">    q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a> = (int) (p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a> - scale * hypotenuse * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle));</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">line</a>(img, p, q, colour, 1, <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ggaf076ef45de481ac96e0ab3dc2c29a777a85fdabe5335c9e6656563dfd7c94fb4f">LINE_AA</a>);</div><div class="line"></div><div class="line">    <span class="comment">// create the arrow hooks</span></div><div class="line">    p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a> = (int) (q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a> + 9 * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle + CV_PI / 4));</div><div class="line">    p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a> = (int) (q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a> + 9 * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle + CV_PI / 4));</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">line</a>(img, p, q, colour, 1, <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ggaf076ef45de481ac96e0ab3dc2c29a777a85fdabe5335c9e6656563dfd7c94fb4f">LINE_AA</a>);</div><div class="line"></div><div class="line">    p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a> = (int) (q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a4c96fa7bdbfe390be5ed356edb274ff3">x</a> + 9 * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle - CV_PI / 4));</div><div class="line">    p.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a> = (int) (q.<a class="code" href="../../db/d4e/classcv_1_1Point__.html#a157337197338ff199e5df1a393022f15">y</a> + 9 * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle - CV_PI / 4));</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">line</a>(img, p, q, colour, 1, <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ggaf076ef45de481ac96e0ab3dc2c29a777a85fdabe5335c9e6656563dfd7c94fb4f">LINE_AA</a>);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">double</span> getOrientation(<span class="keyword">const</span> vector&lt;Point&gt; &amp;pts, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> &amp;img)</div><div class="line">{</div><div class="line">    <span class="comment">//Construct a buffer used by the pca analysis</span></div><div class="line">    <span class="keywordtype">int</span> sz = <span class="keyword">static_cast&lt;</span><span class="keywordtype">int</span><span class="keyword">&gt;</span>(pts.size());</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> data_pts = <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>(sz, 2, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga30a562691cc5987bc88eb7bb7a8faf2b">CV_64F</a>);</div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; data_pts.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abed816466c45234254d25bc59c31245e">rows</a>; i++)</div><div class="line">    {</div><div class="line">        data_pts.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa5d20fc86d41d59e4d71ae93daee9726">at</a>&lt;<span class="keywordtype">double</span>&gt;(i, 0) = pts[i].x;</div><div class="line">        data_pts.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa5d20fc86d41d59e4d71ae93daee9726">at</a>&lt;<span class="keywordtype">double</span>&gt;(i, 1) = pts[i].y;</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="comment">//Perform PCA analysis</span></div><div class="line">    <a class="code" href="../../d3/d8d/classcv_1_1PCA.html">PCA</a> pca_analysis(data_pts, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>(), PCA::DATA_AS_ROW);</div><div class="line"></div><div class="line">    <span class="comment">//Store the center of the object</span></div><div class="line">    <a class="code" href="../../db/d4e/classcv_1_1Point__.html">Point</a> cntr = <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(static_cast&lt;int&gt;(pca_analysis.mean.at&lt;<span class="keywordtype">double</span>&gt;(0, 0)),</div><div class="line">                      static_cast&lt;int&gt;(pca_analysis.mean.at&lt;<span class="keywordtype">double</span>&gt;(0, 1)));</div><div class="line"></div><div class="line">    <span class="comment">//Store the eigenvalues and eigenvectors</span></div><div class="line">    vector&lt;Point2d&gt; eigen_vecs(2);</div><div class="line">    vector&lt;double&gt; eigen_val(2);</div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; 2; i++)</div><div class="line">    {</div><div class="line">        eigen_vecs[i] = <a class="code" href="../../dc/d84/group__core__basic.html#ga32986d8c6fd05949688352abd112509f">Point2d</a>(pca_analysis.eigenvectors.at&lt;<span class="keywordtype">double</span>&gt;(i, 0),</div><div class="line">                                pca_analysis.eigenvectors.at&lt;<span class="keywordtype">double</span>&gt;(i, 1));</div><div class="line"></div><div class="line">        eigen_val[i] = pca_analysis.eigenvalues.at&lt;<span class="keywordtype">double</span>&gt;(i);</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="comment">// Draw the principal components</span></div><div class="line">    <a class="code" href="../../d9/db7/group__datasets__gr.html#gga610754124ced68d1f05760b5948fbb76a6f0d8b2d9e3e947b2a5c1eff9e81ee95">circle</a>(img, cntr, 3, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(255, 0, 255), 2);</div><div class="line">    <a class="code" href="../../db/d4e/classcv_1_1Point__.html">Point</a> p1 = cntr + 0.02 * <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(static_cast&lt;int&gt;(eigen_vecs[0].x * eigen_val[0]), static_cast&lt;int&gt;(eigen_vecs[0].y * eigen_val[0]));</div><div class="line">    <a class="code" href="../../db/d4e/classcv_1_1Point__.html">Point</a> p2 = cntr - 0.02 * <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(static_cast&lt;int&gt;(eigen_vecs[1].x * eigen_val[1]), static_cast&lt;int&gt;(eigen_vecs[1].y * eigen_val[1]));</div><div class="line">    <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p1, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0, 255, 0), 1);</div><div class="line">    <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p2, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(255, 255, 0), 5);</div><div class="line"></div><div class="line">    <span class="keywordtype">double</span> angle = <a class="code" href="../../df/dfc/group__cudev.html#ga1096ba687de70142e095cc791a8bcd65">atan2</a>(eigen_vecs[0].y, eigen_vecs[0].x); <span class="comment">// orientation in radians</span></div><div class="line"><span class="comment"></span></div><div class="line">    <span class="keywordflow">return</span> angle;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">int</span> main(<span class="keywordtype">int</span> argc, <span class="keywordtype">char</span>** argv)</div><div class="line">{</div><div class="line">    <span class="comment">// Load image</span></div><div class="line">    <a class="code" href="../../d0/d2e/classcv_1_1CommandLineParser.html">CommandLineParser</a> parser(argc, argv, <span class="stringliteral">&quot;{@input | pca_test1.jpg | input image}&quot;</span>);</div><div class="line">    parser.about( <span class="stringliteral">&quot;This program demonstrates how to use OpenCV PCA to extract the orientation of an object.\n&quot;</span> );</div><div class="line">    parser.printMessage();</div><div class="line"></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> src = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">imread</a>( <a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">samples::findFile</a>( parser.get&lt;<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>&gt;(<span class="stringliteral">&quot;@input&quot;</span>) ) );</div><div class="line"></div><div class="line">    <span class="comment">// Check if image is loaded successfully</span></div><div class="line">    <span class="keywordflow">if</span>(src.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abbec3525a852e77998aba034813fded4">empty</a>())</div><div class="line">    {</div><div class="line">        cout &lt;&lt; <span class="stringliteral">&quot;Problem loading image!!!&quot;</span> &lt;&lt; endl;</div><div class="line">        <span class="keywordflow">return</span> EXIT_FAILURE;</div><div class="line">    }</div><div class="line"></div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga453d42fe4cb60e5723281a89973ee563">imshow</a>(<span class="stringliteral">&quot;src&quot;</span>, src);</div><div class="line"></div><div class="line">    <span class="comment">// Convert image to grayscale</span></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> gray;</div><div class="line">    <a class="code" href="../../d8/d01/group__imgproc__color__conversions.html#ga397ae87e1288a81d2363b61574eb8cab">cvtColor</a>(src, gray, <a class="code" href="../../d8/d01/group__imgproc__color__conversions.html#gga4e0972be5de079fed4e3a10e24ef5ef0a353a4b8db9040165db4dacb5bcefb6ea">COLOR_BGR2GRAY</a>);</div><div class="line"></div><div class="line">    <span class="comment">// Convert image to binary</span></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> bw;</div><div class="line">    <a class="code" href="../../d7/d1b/group__imgproc__misc.html#gae8a4a146d1ca78c626a53577199e9c57">threshold</a>(gray, bw, 50, 255, <a class="code" href="../../d7/d1b/group__imgproc__misc.html#ggaa9e58d2860d4afa658ef70a9b1115576a147222a96556ebc1d948b372bcd7ac59">THRESH_BINARY</a> | <a class="code" href="../../d7/d1b/group__imgproc__misc.html#ggaa9e58d2860d4afa658ef70a9b1115576a95251923e8e22f368ffa86ba8bce87ff">THRESH_OTSU</a>);</div><div class="line"></div><div class="line">    <span class="comment">// Find all the contours in the thresholded image</span></div><div class="line">    vector&lt;vector&lt;Point&gt; &gt; contours;</div><div class="line">    <a class="code" href="../../d3/dc0/group__imgproc__shape.html#gadf1ad6a0b82947fa1fe3c3d497f260e0">findContours</a>(bw, contours, <a class="code" href="../../d3/dc0/group__imgproc__shape.html#gga819779b9857cc2f8601e6526a3a5bc71a48b9c2cb1056f775ae50bb68288b875e">RETR_LIST</a>, <a class="code" href="../../d3/dc0/group__imgproc__shape.html#gga4303f45752694956374734a03c54d5ffaf7d9a3582d021d5dadcb0e37201a62f8">CHAIN_APPROX_NONE</a>);</div><div class="line"></div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">size_t</span> i = 0; i &lt; contours.size(); i++)</div><div class="line">    {</div><div class="line">        <span class="comment">// Calculate the area of each contour</span></div><div class="line">        <span class="keywordtype">double</span> area = <a class="code" href="../../d3/dc0/group__imgproc__shape.html#ga2c759ed9f497d4a618048a2f56dc97f1">contourArea</a>(contours[i]);</div><div class="line">        <span class="comment">// Ignore contours that are too small or too large</span></div><div class="line">        <span class="keywordflow">if</span> (area &lt; 1e2 || 1e5 &lt; area) <span class="keywordflow">continue</span>;</div><div class="line"></div><div class="line">        <span class="comment">// Draw each contour only for visualisation purposes</span></div><div class="line">        <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga746c0625f1781f1ffc9056259103edbc">drawContours</a>(src, contours, static_cast&lt;int&gt;(i), <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0, 0, 255), 2);</div><div class="line">        <span class="comment">// Find the orientation of each shape</span></div><div class="line">        getOrientation(contours[i], src);</div><div class="line">    }</div><div class="line"></div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga453d42fe4cb60e5723281a89973ee563">imshow</a>(<span class="stringliteral">&quot;output&quot;</span>, src);</div><div class="line"></div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">waitKey</a>();</div><div class="line">    <span class="keywordflow">return</span> EXIT_SUCCESS;</div><div class="line">}</div></div><!-- fragment -->  </div> </li>
</ul>
 <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'><ul>
<li><b>Downloadable code</b>: Click <a href="https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/ml/introduction_to_pca/IntroductionToPCADemo.java">here</a></li>
<li><b>Code at glance:</b> <div class="fragment"><div class="line"><span class="keyword">import</span> java.util.ArrayList;</div><div class="line"><span class="keyword">import</span> java.util.List;</div><div class="line"></div><div class="line"><span class="keyword">import</span> org.opencv.core.Core;</div><div class="line"><span class="keyword">import</span> org.opencv.core.CvType;</div><div class="line"><span class="keyword">import</span> org.opencv.core.Mat;</div><div class="line"><span class="keyword">import</span> org.opencv.core.MatOfPoint;</div><div class="line"><span class="keyword">import</span> org.opencv.core.Point;</div><div class="line"><span class="keyword">import</span> org.opencv.core.Scalar;</div><div class="line"><span class="keyword">import</span> org.opencv.highgui.HighGui;</div><div class="line"><span class="keyword">import</span> org.opencv.imgcodecs.Imgcodecs;</div><div class="line"><span class="keyword">import</span> org.opencv.imgproc.Imgproc;</div><div class="line"></div><div class="line"><span class="comment">//This program demonstrates how to use OpenCV PCA to extract the orientation of an object.</span></div><div class="line"><span class="keyword">class </span>IntroductionToPCA {</div><div class="line">    <span class="keyword">private</span> <span class="keywordtype">void</span> <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(Mat img, <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> p_, <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> q_, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a> colour, <span class="keywordtype">float</span> scale) {</div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> p = <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(p_.x, p_.y);</div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> q = <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(q_.x, q_.y);</div><div class="line">        <span class="keywordtype">double</span> angle = Math.atan2(p.y - q.y, p.x - q.x); <span class="comment">// angle in radians</span></div><div class="line">        <span class="keywordtype">double</span> hypotenuse = Math.sqrt((p.y - q.y) * (p.y - q.y) + (p.x - q.x) * (p.x - q.x));</div><div class="line"></div><div class="line">        <span class="comment">// Here we lengthen the arrow by a factor of scale</span></div><div class="line">        q.x = (int) (p.x - scale * hypotenuse * Math.cos(angle));</div><div class="line">        q.y = (int) (p.y - scale * hypotenuse * Math.sin(angle));</div><div class="line">        Imgproc.line(img, p, q, colour, 1, Imgproc.LINE_AA, 0);</div><div class="line"></div><div class="line">        <span class="comment">// create the arrow hooks</span></div><div class="line">        p.x = (int) (q.x + 9 * Math.cos(angle + Math.PI / 4));</div><div class="line">        p.y = (int) (q.y + 9 * Math.sin(angle + Math.PI / 4));</div><div class="line">        Imgproc.line(img, p, q, colour, 1, Imgproc.LINE_AA, 0);</div><div class="line"></div><div class="line">        p.x = (int) (q.x + 9 * Math.cos(angle - Math.PI / 4));</div><div class="line">        p.y = (int) (q.y + 9 * Math.sin(angle - Math.PI / 4));</div><div class="line">        Imgproc.line(img, p, q, colour, 1, Imgproc.LINE_AA, 0);</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keywordtype">double</span> getOrientation(MatOfPoint ptsMat, Mat img) {</div><div class="line">        List&lt;Point&gt; pts = ptsMat.toList();</div><div class="line">        <span class="comment">// Construct a buffer used by the pca analysis</span></div><div class="line">        <span class="keywordtype">int</span> sz = pts.size();</div><div class="line">        Mat dataPts = <span class="keyword">new</span> Mat(sz, 2, CvType.CV_64F);</div><div class="line">        <span class="keywordtype">double</span>[] dataPtsData = <span class="keyword">new</span> <span class="keywordtype">double</span>[(int) (dataPts.total() * dataPts.channels())];</div><div class="line">        <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; dataPts.rows(); i++) {</div><div class="line">            dataPtsData[i * dataPts.cols()] = pts.get(i).x;</div><div class="line">            dataPtsData[i * dataPts.cols() + 1] = pts.get(i).y;</div><div class="line">        }</div><div class="line">        dataPts.put(0, 0, dataPtsData);</div><div class="line"></div><div class="line">        <span class="comment">// Perform PCA analysis</span></div><div class="line">        Mat mean = <span class="keyword">new</span> Mat();</div><div class="line">        Mat eigenvectors = <span class="keyword">new</span> Mat();</div><div class="line">        Mat eigenvalues = <span class="keyword">new</span> Mat();</div><div class="line">        Core.PCACompute2(dataPts, mean, eigenvectors, eigenvalues);</div><div class="line">        <span class="keywordtype">double</span>[] meanData = <span class="keyword">new</span> <span class="keywordtype">double</span>[(int) (mean.total() * mean.channels())];</div><div class="line">        mean.get(0, 0, meanData);</div><div class="line"></div><div class="line">        <span class="comment">// Store the center of the object</span></div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> cntr = <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(meanData[0], meanData[1]);</div><div class="line"></div><div class="line">        <span class="comment">// Store the eigenvalues and eigenvectors</span></div><div class="line">        <span class="keywordtype">double</span>[] eigenvectorsData = <span class="keyword">new</span> <span class="keywordtype">double</span>[(int) (eigenvectors.total() * eigenvectors.channels())];</div><div class="line">        <span class="keywordtype">double</span>[] eigenvaluesData = <span class="keyword">new</span> <span class="keywordtype">double</span>[(int) (eigenvalues.total() * eigenvalues.channels())];</div><div class="line">        eigenvectors.get(0, 0, eigenvectorsData);</div><div class="line">        eigenvalues.get(0, 0, eigenvaluesData);</div><div class="line"></div><div class="line">        <span class="comment">// Draw the principal components</span></div><div class="line">        Imgproc.circle(img, cntr, 3, <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(255, 0, 255), 2);</div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> p1 = <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(cntr.x + 0.02 * eigenvectorsData[0] * eigenvaluesData[0],</div><div class="line">                cntr.y + 0.02 * eigenvectorsData[1] * eigenvaluesData[0]);</div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> p2 = <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(cntr.x - 0.02 * eigenvectorsData[2] * eigenvaluesData[1],</div><div class="line">                cntr.y - 0.02 * eigenvectorsData[3] * eigenvaluesData[1]);</div><div class="line">        <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p1, <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0, 255, 0), 1);</div><div class="line">        <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p2, <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(255, 255, 0), 5);</div><div class="line"></div><div class="line">        <span class="keywordtype">double</span> angle = Math.atan2(eigenvectorsData[1], eigenvectorsData[0]); <span class="comment">// orientation in radians</span></div><div class="line"><span class="comment"></span></div><div class="line">        <span class="keywordflow">return</span> angle;</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="keyword">public</span> <span class="keywordtype">void</span> run(<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>[] args) {</div><div class="line">        <span class="comment">// Load image</span></div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a> filename = args.length &gt; 0 ? args[0] : <span class="stringliteral">&quot;../data/pca_test1.jpg&quot;</span>;</div><div class="line">        Mat src = Imgcodecs.imread(filename);</div><div class="line"></div><div class="line">        <span class="comment">// Check if image is loaded successfully</span></div><div class="line">        <span class="keywordflow">if</span> (src.empty()) {</div><div class="line">            System.err.println(<span class="stringliteral">&quot;Cannot read image: &quot;</span> + filename);</div><div class="line">            System.exit(0);</div><div class="line">        }</div><div class="line"></div><div class="line">        Mat srcOriginal = src.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adff2ea98da45eae0833e73582dd4a660">clone</a>();</div><div class="line">        HighGui.imshow(<span class="stringliteral">&quot;src&quot;</span>, srcOriginal);</div><div class="line"></div><div class="line">        <span class="comment">// Convert image to grayscale</span></div><div class="line">        Mat gray = <span class="keyword">new</span> Mat();</div><div class="line">        Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);</div><div class="line"></div><div class="line">        <span class="comment">// Convert image to binary</span></div><div class="line">        Mat bw = <span class="keyword">new</span> Mat();</div><div class="line">        Imgproc.threshold(gray, bw, 50, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);</div><div class="line"></div><div class="line">        <span class="comment">// Find all the contours in the thresholded image</span></div><div class="line">        List&lt;MatOfPoint&gt; contours = <span class="keyword">new</span> ArrayList&lt;&gt;();</div><div class="line">        Mat hierarchy = <span class="keyword">new</span> Mat();</div><div class="line">        Imgproc.findContours(bw, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);</div><div class="line"></div><div class="line">        <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; contours.size(); i++) {</div><div class="line">            <span class="comment">// Calculate the area of each contour</span></div><div class="line">            <span class="keywordtype">double</span> area = Imgproc.contourArea(contours.get(i));</div><div class="line">            <span class="comment">// Ignore contours that are too small or too large</span></div><div class="line">            <span class="keywordflow">if</span> (area &lt; 1e2 || 1e5 &lt; area)</div><div class="line">                <span class="keywordflow">continue</span>;</div><div class="line"></div><div class="line">            <span class="comment">// Draw each contour only for visualisation purposes</span></div><div class="line">            Imgproc.drawContours(src, contours, i, <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0, 0, 255), 2);</div><div class="line">            <span class="comment">// Find the orientation of each shape</span></div><div class="line">            getOrientation(contours.get(i), src);</div><div class="line">        }</div><div class="line"></div><div class="line">        HighGui.imshow(<span class="stringliteral">&quot;output&quot;</span>, src);</div><div class="line"></div><div class="line">        HighGui.waitKey();</div><div class="line">        System.exit(0);</div><div class="line">    }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="keyword">class </span>IntroductionToPCADemo {</div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keywordtype">void</span> main(<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>[] args) {</div><div class="line">        <span class="comment">// Load the native OpenCV library</span></div><div class="line">        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);</div><div class="line"></div><div class="line">        <span class="keyword">new</span> IntroductionToPCA().run(args);</div><div class="line">    }</div><div class="line">}</div></div><!-- fragment -->  </div> </li>
</ul>
 <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'><ul>
<li><b>Downloadable code</b>: Click <a href="https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/ml/introduction_to_pca/introduction_to_pca.py">here</a></li>
<li><b>Code at glance:</b> <div class="fragment"><div class="line"><span class="keyword">from</span> __future__ <span class="keyword">import</span> print_function</div><div class="line"><span class="keyword">from</span> __future__ <span class="keyword">import</span> division</div><div class="line"><span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">import</span> argparse</div><div class="line"><span class="keyword">from</span> math <span class="keyword">import</span> atan2, cos, sin, sqrt, pi</div><div class="line"></div><div class="line"><span class="keyword">def </span><a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, p_, q_, colour, scale):</div><div class="line">    p = list(p_)</div><div class="line">    q = list(q_)</div><div class="line">    </div><div class="line">    angle = <a class="code" href="../../df/dfc/group__cudev.html#ga1096ba687de70142e095cc791a8bcd65">atan2</a>(p[1] - q[1], p[0] - q[0]) <span class="comment"># angle in radians</span></div><div class="line">    hypotenuse = <a class="code" href="../../d0/de1/group__core.html#ga9070b6a3f093dd952d973819b06f4906">sqrt</a>((p[1] - q[1]) * (p[1] - q[1]) + (p[0] - q[0]) * (p[0] - q[0]))</div><div class="line"></div><div class="line">    <span class="comment"># Here we lengthen the arrow by a factor of scale</span></div><div class="line">    q[0] = p[0] - scale * hypotenuse * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle)</div><div class="line">    q[1] = p[1] - scale * hypotenuse * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle)</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">cv.line</a>(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), colour, 1, cv.LINE_AA)</div><div class="line"></div><div class="line">    <span class="comment"># create the arrow hooks</span></div><div class="line">    p[0] = q[0] + 9 * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle + pi / 4)</div><div class="line">    p[1] = q[1] + 9 * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle + pi / 4)</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">cv.line</a>(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), colour, 1, cv.LINE_AA)</div><div class="line"></div><div class="line">    p[0] = q[0] + 9 * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle - pi / 4)</div><div class="line">    p[1] = q[1] + 9 * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle - pi / 4)</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">cv.line</a>(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), colour, 1, cv.LINE_AA)</div><div class="line">    </div><div class="line"></div><div class="line"><span class="keyword">def </span>getOrientation(pts, img):</div><div class="line">    </div><div class="line">    sz = len(pts)</div><div class="line">    data_pts = np.empty((sz, 2), dtype=np.float64)</div><div class="line">    <span class="keywordflow">for</span> i <span class="keywordflow">in</span> range(data_pts.shape[0]):</div><div class="line">        data_pts[i,0] = pts[i,0,0]</div><div class="line">        data_pts[i,1] = pts[i,0,1]</div><div class="line"></div><div class="line">    <span class="comment"># Perform PCA analysis</span></div><div class="line">    mean = np.empty((0))</div><div class="line">    mean, eigenvectors, eigenvalues = cv.PCACompute2(data_pts, mean)</div><div class="line"></div><div class="line">    <span class="comment"># Store the center of the object</span></div><div class="line">    cntr = (int(mean[0,0]), int(mean[0,1]))</div><div class="line">    </div><div class="line"></div><div class="line">    </div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#gaf10604b069374903dbd0f0488cb43670">cv.circle</a>(img, cntr, 3, (255, 0, 255), 2)</div><div class="line">    p1 = (cntr[0] + 0.02 * eigenvectors[0,0] * eigenvalues[0,0], cntr[1] + 0.02 * eigenvectors[0,1] * eigenvalues[0,0])</div><div class="line">    p2 = (cntr[0] - 0.02 * eigenvectors[1,0] * eigenvalues[1,0], cntr[1] - 0.02 * eigenvectors[1,1] * eigenvalues[1,0])</div><div class="line">    <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p1, (0, 255, 0), 1)</div><div class="line">    <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p2, (255, 255, 0), 5)</div><div class="line"></div><div class="line">    angle = <a class="code" href="../../df/dfc/group__cudev.html#ga1096ba687de70142e095cc791a8bcd65">atan2</a>(eigenvectors[0,1], eigenvectors[0,0]) <span class="comment"># orientation in radians</span></div><div class="line">    </div><div class="line"></div><div class="line">    <span class="keywordflow">return</span> angle</div><div class="line"></div><div class="line"></div><div class="line">parser = argparse.ArgumentParser(description=<span class="stringliteral">&#39;Code for Introduction to Principal Component Analysis (PCA) tutorial.\</span></div><div class="line"><span class="stringliteral">                                              This program demonstrates how to use OpenCV PCA to extract the orientation of an object.&#39;</span>)</div><div class="line">parser.add_argument(<span class="stringliteral">&#39;--input&#39;</span>, help=<span class="stringliteral">&#39;Path to input image.&#39;</span>, default=<span class="stringliteral">&#39;pca_test1.jpg&#39;</span>)</div><div class="line">args = parser.parse_args()</div><div class="line"></div><div class="line">src = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">cv.samples.findFile</a>(args.input))</div><div class="line"><span class="comment"># Check if image is loaded successfully</span></div><div class="line"><span class="keywordflow">if</span> src <span class="keywordflow">is</span> <span class="keywordtype">None</span>:</div><div class="line">    <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&#39;Could not open or find the image: &#39;</span>, args.input)</div><div class="line">    exit(0)</div><div class="line"></div><div class="line"><a class="code" href="../../df/d24/group__highgui__opengl.html#gaae7e90aa3415c68dba22a5ff2cefc25d">cv.imshow</a>(<span class="stringliteral">&#39;src&#39;</span>, src)</div><div class="line"></div><div class="line"><span class="comment"># Convert image to grayscale</span></div><div class="line">gray = <a class="code" href="../../d8/d01/group__imgproc__color__conversions.html#ga397ae87e1288a81d2363b61574eb8cab">cv.cvtColor</a>(src, cv.COLOR_BGR2GRAY)</div><div class="line"></div><div class="line"><span class="comment"># Convert image to binary</span></div><div class="line">_, bw = <a class="code" href="../../d7/d1b/group__imgproc__misc.html#gae8a4a146d1ca78c626a53577199e9c57">cv.threshold</a>(gray, 50, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)</div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line">contours, _ = <a class="code" href="../../d3/dc0/group__imgproc__shape.html#gae4156f04053c44f886e387cff0ef6e08">cv.findContours</a>(bw, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)</div><div class="line"></div><div class="line"><span class="keywordflow">for</span> i, c <span class="keywordflow">in</span> enumerate(contours):</div><div class="line">    <span class="comment"># Calculate the area of each contour</span></div><div class="line">    area = <a class="code" href="../../d3/dc0/group__imgproc__shape.html#ga2c759ed9f497d4a618048a2f56dc97f1">cv.contourArea</a>(c)</div><div class="line">    <span class="comment"># Ignore contours that are too small or too large</span></div><div class="line">    <span class="keywordflow">if</span> area &lt; 1e2 <span class="keywordflow">or</span> 1e5 &lt; area:</div><div class="line">        <span class="keywordflow">continue</span></div><div class="line"></div><div class="line">    <span class="comment"># Draw each contour only for visualisation purposes</span></div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga746c0625f1781f1ffc9056259103edbc">cv.drawContours</a>(src, contours, i, (0, 0, 255), 2)</div><div class="line">    <span class="comment"># Find the orientation of each shape</span></div><div class="line">    getOrientation(c, src)</div><div class="line"></div><div class="line"></div><div class="line"><a class="code" href="../../df/d24/group__highgui__opengl.html#gaae7e90aa3415c68dba22a5ff2cefc25d">cv.imshow</a>(<span class="stringliteral">&#39;output&#39;</span>, src)</div><div class="line"><a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">cv.waitKey</a>()</div></div><!-- fragment -->  </div> </li>
</ul>
<dl class="section note"><dt>Note</dt><dd>Another example using PCA for dimensionality reduction while maintaining an amount of variance can be found at <a href="https://github.com/opencv/opencv/tree/master/samples/cpp/pca.cpp">opencv_source_code/samples/cpp/pca.cpp</a></dd></dl>
<h2>Explanation </h2>
<ul>
<li><b>Read image and convert it to binary</b></li>
</ul>
<p>Here we apply the necessary pre-processing procedures in order to be able to detect the objects of interest.</p>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">    <span class="comment">// Load image</span></div><div class="line">    CommandLineParser parser(argc, argv, <span class="stringliteral">&quot;{@input | pca_test1.jpg | input image}&quot;</span>);</div><div class="line">    parser.about( <span class="stringliteral">&quot;This program demonstrates how to use OpenCV PCA to extract the orientation of an object.\n&quot;</span> );</div><div class="line">    parser.printMessage();</div><div class="line"></div><div class="line">    Mat src = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">imread</a>( <a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">samples::findFile</a>( parser.get&lt;<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>&gt;(<span class="stringliteral">&quot;@input&quot;</span>) ) );</div><div class="line"></div><div class="line">    <span class="comment">// Check if image is loaded successfully</span></div><div class="line">    <span class="keywordflow">if</span>(src.empty())</div><div class="line">    {</div><div class="line">        cout &lt;&lt; <span class="stringliteral">&quot;Problem loading image!!!&quot;</span> &lt;&lt; endl;</div><div class="line">        <span class="keywordflow">return</span> EXIT_FAILURE;</div><div class="line">    }</div><div class="line"></div><div class="line">    <a class="code" href="../../d7/dfc/group__highgui.html#ga453d42fe4cb60e5723281a89973ee563">imshow</a>(<span class="stringliteral">&quot;src&quot;</span>, src);</div><div class="line"></div><div class="line">    <span class="comment">// Convert image to grayscale</span></div><div class="line">    Mat gray;</div><div class="line">    <a class="code" href="../../d8/d01/group__imgproc__color__conversions.html#ga397ae87e1288a81d2363b61574eb8cab">cvtColor</a>(src, gray, <a class="code" href="../../d8/d01/group__imgproc__color__conversions.html#gga4e0972be5de079fed4e3a10e24ef5ef0a353a4b8db9040165db4dacb5bcefb6ea">COLOR_BGR2GRAY</a>);</div><div class="line"></div><div class="line">    <span class="comment">// Convert image to binary</span></div><div class="line">    Mat bw;</div><div class="line">    <a class="code" href="../../d7/d1b/group__imgproc__misc.html#gae8a4a146d1ca78c626a53577199e9c57">threshold</a>(gray, bw, 50, 255, <a class="code" href="../../d7/d1b/group__imgproc__misc.html#ggaa9e58d2860d4afa658ef70a9b1115576a147222a96556ebc1d948b372bcd7ac59">THRESH_BINARY</a> | <a class="code" href="../../d7/d1b/group__imgproc__misc.html#ggaa9e58d2860d4afa658ef70a9b1115576a95251923e8e22f368ffa86ba8bce87ff">THRESH_OTSU</a>);</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">        <span class="comment">// Load image</span></div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a> filename = args.length &gt; 0 ? args[0] : <span class="stringliteral">&quot;../data/pca_test1.jpg&quot;</span>;</div><div class="line">        Mat src = Imgcodecs.imread(filename);</div><div class="line"></div><div class="line">        <span class="comment">// Check if image is loaded successfully</span></div><div class="line">        <span class="keywordflow">if</span> (src.empty()) {</div><div class="line">            System.err.println(<span class="stringliteral">&quot;Cannot read image: &quot;</span> + filename);</div><div class="line">            System.exit(0);</div><div class="line">        }</div><div class="line"></div><div class="line">        Mat srcOriginal = src.clone();</div><div class="line">        HighGui.imshow(<span class="stringliteral">&quot;src&quot;</span>, srcOriginal);</div><div class="line"></div><div class="line">        <span class="comment">// Convert image to grayscale</span></div><div class="line">        Mat gray = <span class="keyword">new</span> Mat();</div><div class="line">        Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);</div><div class="line"></div><div class="line">        <span class="comment">// Convert image to binary</span></div><div class="line">        Mat bw = <span class="keyword">new</span> Mat();</div><div class="line">        Imgproc.threshold(gray, bw, 50, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line"><span class="comment"># Load image</span></div><div class="line">parser = argparse.ArgumentParser(description=<span class="stringliteral">&#39;Code for Introduction to Principal Component Analysis (PCA) tutorial.\</span></div><div class="line"><span class="stringliteral">                                              This program demonstrates how to use OpenCV PCA to extract the orientation of an object.&#39;</span>)</div><div class="line">parser.add_argument(<span class="stringliteral">&#39;--input&#39;</span>, help=<span class="stringliteral">&#39;Path to input image.&#39;</span>, default=<span class="stringliteral">&#39;pca_test1.jpg&#39;</span>)</div><div class="line">args = parser.parse_args()</div><div class="line"></div><div class="line">src = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<a class="code" href="../../d6/dba/group__core__utils__samples.html#ga3a33b00033b46c698ff6340d95569c13">cv.samples.findFile</a>(args.input))</div><div class="line"><span class="comment"># Check if image is loaded successfully</span></div><div class="line"><span class="keywordflow">if</span> src <span class="keywordflow">is</span> <span class="keywordtype">None</span>:</div><div class="line">    <a class="code" href="../../df/d57/namespacecv_1_1dnn.html#a701210a0203f2786cbfd04b2bd56da47">print</a>(<span class="stringliteral">&#39;Could not open or find the image: &#39;</span>, args.input)</div><div class="line">    exit(0)</div><div class="line"></div><div class="line"><a class="code" href="../../df/d24/group__highgui__opengl.html#gaae7e90aa3415c68dba22a5ff2cefc25d">cv.imshow</a>(<span class="stringliteral">&#39;src&#39;</span>, src)</div><div class="line"></div><div class="line"><span class="comment"># Convert image to grayscale</span></div><div class="line">gray = <a class="code" href="../../d8/d01/group__imgproc__color__conversions.html#ga397ae87e1288a81d2363b61574eb8cab">cv.cvtColor</a>(src, cv.COLOR_BGR2GRAY)</div><div class="line"></div><div class="line"><span class="comment"># Convert image to binary</span></div><div class="line">_, bw = <a class="code" href="../../d7/d1b/group__imgproc__misc.html#gae8a4a146d1ca78c626a53577199e9c57">cv.threshold</a>(gray, 50, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)</div></div><!-- fragment --> </div> <ul>
<li><b>Extract objects of interest</b></li>
</ul>
<p>Then find and filter contours by size and obtain the orientation of the remaining ones.</p>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">    <span class="comment">// Find all the contours in the thresholded image</span></div><div class="line">    vector&lt;vector&lt;Point&gt; &gt; contours;</div><div class="line">    <a class="code" href="../../d3/dc0/group__imgproc__shape.html#gadf1ad6a0b82947fa1fe3c3d497f260e0">findContours</a>(bw, contours, <a class="code" href="../../d3/dc0/group__imgproc__shape.html#gga819779b9857cc2f8601e6526a3a5bc71a48b9c2cb1056f775ae50bb68288b875e">RETR_LIST</a>, <a class="code" href="../../d3/dc0/group__imgproc__shape.html#gga4303f45752694956374734a03c54d5ffaf7d9a3582d021d5dadcb0e37201a62f8">CHAIN_APPROX_NONE</a>);</div><div class="line"></div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">size_t</span> i = 0; i &lt; contours.size(); i++)</div><div class="line">    {</div><div class="line">        <span class="comment">// Calculate the area of each contour</span></div><div class="line">        <span class="keywordtype">double</span> area = <a class="code" href="../../d3/dc0/group__imgproc__shape.html#ga2c759ed9f497d4a618048a2f56dc97f1">contourArea</a>(contours[i]);</div><div class="line">        <span class="comment">// Ignore contours that are too small or too large</span></div><div class="line">        <span class="keywordflow">if</span> (area &lt; 1e2 || 1e5 &lt; area) <span class="keywordflow">continue</span>;</div><div class="line"></div><div class="line">        <span class="comment">// Draw each contour only for visualisation purposes</span></div><div class="line">        <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga746c0625f1781f1ffc9056259103edbc">drawContours</a>(src, contours, static_cast&lt;int&gt;(i), <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0, 0, 255), 2);</div><div class="line">        <span class="comment">// Find the orientation of each shape</span></div><div class="line">        getOrientation(contours[i], src);</div><div class="line">    }</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">        <span class="comment">// Find all the contours in the thresholded image</span></div><div class="line">        List&lt;MatOfPoint&gt; contours = <span class="keyword">new</span> ArrayList&lt;&gt;();</div><div class="line">        Mat hierarchy = <span class="keyword">new</span> Mat();</div><div class="line">        Imgproc.findContours(bw, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);</div><div class="line"></div><div class="line">        <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; contours.size(); i++) {</div><div class="line">            <span class="comment">// Calculate the area of each contour</span></div><div class="line">            <span class="keywordtype">double</span> area = Imgproc.contourArea(contours.get(i));</div><div class="line">            <span class="comment">// Ignore contours that are too small or too large</span></div><div class="line">            <span class="keywordflow">if</span> (area &lt; 1e2 || 1e5 &lt; area)</div><div class="line">                <span class="keywordflow">continue</span>;</div><div class="line"></div><div class="line">            <span class="comment">// Draw each contour only for visualisation purposes</span></div><div class="line">            Imgproc.drawContours(src, contours, i, <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0, 0, 255), 2);</div><div class="line">            <span class="comment">// Find the orientation of each shape</span></div><div class="line">            getOrientation(contours.get(i), src);</div><div class="line">        }</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line"><span class="comment"># Find all the contours in the thresholded image</span></div><div class="line">contours, _ = <a class="code" href="../../d3/dc0/group__imgproc__shape.html#gae4156f04053c44f886e387cff0ef6e08">cv.findContours</a>(bw, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)</div><div class="line"></div><div class="line"><span class="keywordflow">for</span> i, c <span class="keywordflow">in</span> enumerate(contours):</div><div class="line">    <span class="comment"># Calculate the area of each contour</span></div><div class="line">    area = <a class="code" href="../../d3/dc0/group__imgproc__shape.html#ga2c759ed9f497d4a618048a2f56dc97f1">cv.contourArea</a>(c)</div><div class="line">    <span class="comment"># Ignore contours that are too small or too large</span></div><div class="line">    <span class="keywordflow">if</span> area &lt; 1e2 <span class="keywordflow">or</span> 1e5 &lt; area:</div><div class="line">        <span class="keywordflow">continue</span></div><div class="line"></div><div class="line">    <span class="comment"># Draw each contour only for visualisation purposes</span></div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga746c0625f1781f1ffc9056259103edbc">cv.drawContours</a>(src, contours, i, (0, 0, 255), 2)</div><div class="line">    <span class="comment"># Find the orientation of each shape</span></div><div class="line">    getOrientation(c, src)</div></div><!-- fragment --> </div> <ul>
<li><b>Extract orientation</b></li>
</ul>
<p>Orientation is extracted by the call of getOrientation() function, which performs all the PCA procedure.</p>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">    <span class="comment">//Construct a buffer used by the pca analysis</span></div><div class="line">    <span class="keywordtype">int</span> sz = <span class="keyword">static_cast&lt;</span><span class="keywordtype">int</span><span class="keyword">&gt;</span>(pts.size());</div><div class="line">    Mat data_pts = Mat(sz, 2, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga30a562691cc5987bc88eb7bb7a8faf2b">CV_64F</a>);</div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; data_pts.rows; i++)</div><div class="line">    {</div><div class="line">        data_pts.at&lt;<span class="keywordtype">double</span>&gt;(i, 0) = pts[i].x;</div><div class="line">        data_pts.at&lt;<span class="keywordtype">double</span>&gt;(i, 1) = pts[i].y;</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="comment">//Perform PCA analysis</span></div><div class="line">    PCA pca_analysis(data_pts, Mat(), PCA::DATA_AS_ROW);</div><div class="line"></div><div class="line">    <span class="comment">//Store the center of the object</span></div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> cntr = <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(static_cast&lt;int&gt;(pca_analysis.mean.at&lt;<span class="keywordtype">double</span>&gt;(0, 0)),</div><div class="line">                      static_cast&lt;int&gt;(pca_analysis.mean.at&lt;<span class="keywordtype">double</span>&gt;(0, 1)));</div><div class="line"></div><div class="line">    <span class="comment">//Store the eigenvalues and eigenvectors</span></div><div class="line">    vector&lt;Point2d&gt; eigen_vecs(2);</div><div class="line">    vector&lt;double&gt; eigen_val(2);</div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; 2; i++)</div><div class="line">    {</div><div class="line">        eigen_vecs[i] = <a class="code" href="../../dc/d84/group__core__basic.html#ga32986d8c6fd05949688352abd112509f">Point2d</a>(pca_analysis.eigenvectors.at&lt;<span class="keywordtype">double</span>&gt;(i, 0),</div><div class="line">                                pca_analysis.eigenvectors.at&lt;<span class="keywordtype">double</span>&gt;(i, 1));</div><div class="line"></div><div class="line">        eigen_val[i] = pca_analysis.eigenvalues.at&lt;<span class="keywordtype">double</span>&gt;(i);</div><div class="line">    }</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">        <span class="comment">// Construct a buffer used by the pca analysis</span></div><div class="line">        <span class="keywordtype">int</span> sz = pts.size();</div><div class="line">        Mat dataPts = <span class="keyword">new</span> Mat(sz, 2, CvType.CV_64F);</div><div class="line">        <span class="keywordtype">double</span>[] dataPtsData = <span class="keyword">new</span> <span class="keywordtype">double</span>[(int) (dataPts.total() * dataPts.channels())];</div><div class="line">        <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; dataPts.rows(); i++) {</div><div class="line">            dataPtsData[i * dataPts.cols()] = pts.get(i).x;</div><div class="line">            dataPtsData[i * dataPts.cols() + 1] = pts.get(i).y;</div><div class="line">        }</div><div class="line">        dataPts.put(0, 0, dataPtsData);</div><div class="line"></div><div class="line">        <span class="comment">// Perform PCA analysis</span></div><div class="line">        Mat mean = <span class="keyword">new</span> Mat();</div><div class="line">        Mat eigenvectors = <span class="keyword">new</span> Mat();</div><div class="line">        Mat eigenvalues = <span class="keyword">new</span> Mat();</div><div class="line">        Core.PCACompute2(dataPts, mean, eigenvectors, eigenvalues);</div><div class="line">        <span class="keywordtype">double</span>[] meanData = <span class="keyword">new</span> <span class="keywordtype">double</span>[(int) (mean.total() * mean.channels())];</div><div class="line">        mean.get(0, 0, meanData);</div><div class="line"></div><div class="line">        <span class="comment">// Store the center of the object</span></div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> cntr = <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(meanData[0], meanData[1]);</div><div class="line"></div><div class="line">        <span class="comment">// Store the eigenvalues and eigenvectors</span></div><div class="line">        <span class="keywordtype">double</span>[] eigenvectorsData = <span class="keyword">new</span> <span class="keywordtype">double</span>[(int) (eigenvectors.total() * eigenvectors.channels())];</div><div class="line">        <span class="keywordtype">double</span>[] eigenvaluesData = <span class="keyword">new</span> <span class="keywordtype">double</span>[(int) (eigenvalues.total() * eigenvalues.channels())];</div><div class="line">        eigenvectors.get(0, 0, eigenvectorsData);</div><div class="line">        eigenvalues.get(0, 0, eigenvaluesData);</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line">    <span class="comment"># Construct a buffer used by the pca analysis</span></div><div class="line">    sz = len(pts)</div><div class="line">    data_pts = np.empty((sz, 2), dtype=np.float64)</div><div class="line">    <span class="keywordflow">for</span> i <span class="keywordflow">in</span> range(data_pts.shape[0]):</div><div class="line">        data_pts[i,0] = pts[i,0,0]</div><div class="line">        data_pts[i,1] = pts[i,0,1]</div><div class="line"></div><div class="line">    <span class="comment"># Perform PCA analysis</span></div><div class="line">    mean = np.empty((0))</div><div class="line">    mean, eigenvectors, eigenvalues = cv.PCACompute2(data_pts, mean)</div><div class="line"></div><div class="line">    <span class="comment"># Store the center of the object</span></div><div class="line">    cntr = (int(mean[0,0]), int(mean[0,1]))</div></div><!-- fragment --> </div> <p>First the data need to be arranged in a matrix with size n x 2, where n is the number of data points we have. Then we can perform that PCA analysis. The calculated mean (i.e. center of mass) is stored in the <em>cntr</em> variable and the eigenvectors and eigenvalues are stored in the corresponding std::vector’s.</p>
<ul>
<li><b>Visualize result</b></li>
</ul>
<p>The final result is visualized through the <a class="el" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2" title="Draw coordinate system axis from pose estimation. ">drawAxis()</a> function, where the principal components are drawn in lines, and each eigenvector is multiplied by its eigenvalue and translated to the mean position.</p>
 <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">    <span class="comment">// Draw the principal components</span></div><div class="line">    <a class="code" href="../../d9/db7/group__datasets__gr.html#gga610754124ced68d1f05760b5948fbb76a6f0d8b2d9e3e947b2a5c1eff9e81ee95">circle</a>(img, cntr, 3, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(255, 0, 255), 2);</div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> p1 = cntr + 0.02 * <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(static_cast&lt;int&gt;(eigen_vecs[0].x * eigen_val[0]), static_cast&lt;int&gt;(eigen_vecs[0].y * eigen_val[0]));</div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> p2 = cntr - 0.02 * <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(static_cast&lt;int&gt;(eigen_vecs[1].x * eigen_val[1]), static_cast&lt;int&gt;(eigen_vecs[1].y * eigen_val[1]));</div><div class="line">    <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p1, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0, 255, 0), 1);</div><div class="line">    <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p2, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(255, 255, 0), 5);</div><div class="line"></div><div class="line">    <span class="keywordtype">double</span> angle = <a class="code" href="../../df/dfc/group__cudev.html#ga1096ba687de70142e095cc791a8bcd65">atan2</a>(eigen_vecs[0].y, eigen_vecs[0].x); <span class="comment">// orientation in radians</span></div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">        <span class="comment">// Draw the principal components</span></div><div class="line">        Imgproc.circle(img, cntr, 3, <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(255, 0, 255), 2);</div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> p1 = <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(cntr.x + 0.02 * eigenvectorsData[0] * eigenvaluesData[0],</div><div class="line">                cntr.y + 0.02 * eigenvectorsData[1] * eigenvaluesData[0]);</div><div class="line">        <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> p2 = <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a>(cntr.x - 0.02 * eigenvectorsData[2] * eigenvaluesData[1],</div><div class="line">                cntr.y - 0.02 * eigenvectorsData[3] * eigenvaluesData[1]);</div><div class="line">        <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p1, <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0, 255, 0), 1);</div><div class="line">        <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p2, <span class="keyword">new</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(255, 255, 0), 5);</div><div class="line"></div><div class="line">        <span class="keywordtype">double</span> angle = Math.atan2(eigenvectorsData[1], eigenvectorsData[0]); <span class="comment">// orientation in radians</span></div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line">    <span class="comment"># Draw the principal components</span></div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#gaf10604b069374903dbd0f0488cb43670">cv.circle</a>(img, cntr, 3, (255, 0, 255), 2)</div><div class="line">    p1 = (cntr[0] + 0.02 * eigenvectors[0,0] * eigenvalues[0,0], cntr[1] + 0.02 * eigenvectors[0,1] * eigenvalues[0,0])</div><div class="line">    p2 = (cntr[0] - 0.02 * eigenvectors[1,0] * eigenvalues[1,0], cntr[1] - 0.02 * eigenvectors[1,1] * eigenvalues[1,0])</div><div class="line">    <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p1, (0, 255, 0), 1)</div><div class="line">    <a class="code" href="../../d9/d6a/group__aruco.html#ga16fda651a4e6a8f5747a85cbb6b400a2">drawAxis</a>(img, cntr, p2, (255, 255, 0), 5)</div><div class="line"></div><div class="line">    angle = <a class="code" href="../../df/dfc/group__cudev.html#ga1096ba687de70142e095cc791a8bcd65">atan2</a>(eigenvectors[0,1], eigenvectors[0,0]) <span class="comment"># orientation in radians</span></div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'> <div class="fragment"><div class="line">    <span class="keywordtype">double</span> angle = <a class="code" href="../../df/dfc/group__cudev.html#ga1096ba687de70142e095cc791a8bcd65">atan2</a>( (<span class="keywordtype">double</span>) p.y - q.y, (<span class="keywordtype">double</span>) p.x - q.x ); <span class="comment">// angle in radians</span></div><div class="line">    <span class="keywordtype">double</span> hypotenuse = <a class="code" href="../../d0/de1/group__core.html#ga9070b6a3f093dd952d973819b06f4906">sqrt</a>( (<span class="keywordtype">double</span>) (p.y - q.y) * (p.y - q.y) + (p.x - q.x) * (p.x - q.x));</div><div class="line"></div><div class="line">    <span class="comment">// Here we lengthen the arrow by a factor of scale</span></div><div class="line">    q.x = (int) (p.x - scale * hypotenuse * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle));</div><div class="line">    q.y = (int) (p.y - scale * hypotenuse * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle));</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">line</a>(img, p, q, colour, 1, <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ggaf076ef45de481ac96e0ab3dc2c29a777a85fdabe5335c9e6656563dfd7c94fb4f">LINE_AA</a>);</div><div class="line"></div><div class="line">    <span class="comment">// create the arrow hooks</span></div><div class="line">    p.x = (int) (q.x + 9 * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle + CV_PI / 4));</div><div class="line">    p.y = (int) (q.y + 9 * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle + CV_PI / 4));</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">line</a>(img, p, q, colour, 1, <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ggaf076ef45de481ac96e0ab3dc2c29a777a85fdabe5335c9e6656563dfd7c94fb4f">LINE_AA</a>);</div><div class="line"></div><div class="line">    p.x = (int) (q.x + 9 * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle - CV_PI / 4));</div><div class="line">    p.y = (int) (q.y + 9 * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle - CV_PI / 4));</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">line</a>(img, p, q, colour, 1, <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ggaf076ef45de481ac96e0ab3dc2c29a777a85fdabe5335c9e6656563dfd7c94fb4f">LINE_AA</a>);</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'> <div class="fragment"><div class="line">        <span class="keywordtype">double</span> angle = Math.atan2(p.y - q.y, p.x - q.x); <span class="comment">// angle in radians</span></div><div class="line">        <span class="keywordtype">double</span> hypotenuse = Math.sqrt((p.y - q.y) * (p.y - q.y) + (p.x - q.x) * (p.x - q.x));</div><div class="line"></div><div class="line">        <span class="comment">// Here we lengthen the arrow by a factor of scale</span></div><div class="line">        q.x = (int) (p.x - scale * hypotenuse * Math.cos(angle));</div><div class="line">        q.y = (int) (p.y - scale * hypotenuse * Math.sin(angle));</div><div class="line">        Imgproc.line(img, p, q, colour, 1, Imgproc.LINE_AA, 0);</div><div class="line"></div><div class="line">        <span class="comment">// create the arrow hooks</span></div><div class="line">        p.x = (int) (q.x + 9 * Math.cos(angle + Math.PI / 4));</div><div class="line">        p.y = (int) (q.y + 9 * Math.sin(angle + Math.PI / 4));</div><div class="line">        Imgproc.line(img, p, q, colour, 1, Imgproc.LINE_AA, 0);</div><div class="line"></div><div class="line">        p.x = (int) (q.x + 9 * Math.cos(angle - Math.PI / 4));</div><div class="line">        p.y = (int) (q.y + 9 * Math.sin(angle - Math.PI / 4));</div><div class="line">        Imgproc.line(img, p, q, colour, 1, Imgproc.LINE_AA, 0);</div></div><!-- fragment --> </div>  <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'> <div class="fragment"><div class="line">    angle = <a class="code" href="../../df/dfc/group__cudev.html#ga1096ba687de70142e095cc791a8bcd65">atan2</a>(p[1] - q[1], p[0] - q[0]) <span class="comment"># angle in radians</span></div><div class="line">    hypotenuse = <a class="code" href="../../d0/de1/group__core.html#ga9070b6a3f093dd952d973819b06f4906">sqrt</a>((p[1] - q[1]) * (p[1] - q[1]) + (p[0] - q[0]) * (p[0] - q[0]))</div><div class="line"></div><div class="line">    <span class="comment"># Here we lengthen the arrow by a factor of scale</span></div><div class="line">    q[0] = p[0] - scale * hypotenuse * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle)</div><div class="line">    q[1] = p[1] - scale * hypotenuse * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle)</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">cv.line</a>(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), colour, 1, cv.LINE_AA)</div><div class="line"></div><div class="line">    <span class="comment"># create the arrow hooks</span></div><div class="line">    p[0] = q[0] + 9 * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle + pi / 4)</div><div class="line">    p[1] = q[1] + 9 * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle + pi / 4)</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">cv.line</a>(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), colour, 1, cv.LINE_AA)</div><div class="line"></div><div class="line">    p[0] = q[0] + 9 * <a class="code" href="../../d0/de1/group__core.html#gaf0f2fe47183d063fb7415097fbadb570">cos</a>(angle - pi / 4)</div><div class="line">    p[1] = q[1] + 9 * <a class="code" href="../../d0/de1/group__core.html#ga53a8656033a51db64caa72ee9d4e93b4">sin</a>(angle - pi / 4)</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2">cv.line</a>(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), colour, 1, cv.LINE_AA)</div></div><!-- fragment --> </div> <h2>Results </h2>
<p>The code opens an image, finds the orientation of the detected objects of interest and then visualizes the result by drawing the contours of the detected objects of interest, the center point, and the x-axis, y-axis regarding the extracted orientation.</p>
<div class="image">
<img src="../../pca_test1.jpg" alt="pca_test1.jpg"/>
</div>
<div class="image">
<img src="../../pca_output.png" alt="pca_output.png"/>
</div>
 </div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:37 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
